package cn.demoxy.shiro;

import cn.demoxy.mapper.DemoUserRoleMapper;
import cn.demoxy.model.entity.DemoMenu;
import cn.demoxy.model.entity.DemoUser;
import cn.demoxy.model.entity.DemoUserRole;
import cn.demoxy.model.entity.JWTToken;
import cn.demoxy.service.IDemoMenuService;
import cn.demoxy.service.IDemoUserService;
import cn.demoxy.utils.JWTUtils;
import cn.demoxy.utils.RedisUtils;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @auther demo
 * @date 2022/6/13 21:31
 * 自定义realm
 */
@Component
public class ExampleRealm extends AuthorizingRealm {

    @Autowired
    private IDemoUserService userService;

    @Autowired
    private IDemoMenuService menuService;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //通过令牌获取用户名
        String username = JWTUtils.getUsername(principals.toString());
        DemoUser user = userService.findByUserName(username);
        //判断用户是否存在角色
        if (!CollectionUtils.isEmpty(user.getRoles())) {
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            user.getRoles().forEach(role -> {
                //授权角色权限
                simpleAuthorizationInfo.addRole(role.getRoleCode());
                //通过角色id获取接口资源
                List<DemoMenu> perms = menuService.getMenuByRoleId(role.getId());
                if (perms.size() > 0) {
                    perms.forEach(perm -> {
                        if (StringUtils.hasText(perm.getPermission())) {
                            //添加接口资源权限
                            simpleAuthorizationInfo.addStringPermission(perm.getPermission());
                        }
                    });
                }
            });
            return simpleAuthorizationInfo;
        }
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //根据身份信息获取令牌
        String token = (String) authenticationToken.getCredentials();
        String username = null;
        try {
            // 解密获得username
            username = JWTUtils.getUsername(token);
        } catch (Exception e) {
            throw new AuthenticationException("token非法");
        }

        if (username == null) {
            throw new AuthenticationException("token中无用户名");
        }
        DemoUser user = userService.findByUserName(username);
        if (user == null) {
            throw new AuthenticationException("该用户不存在");
        }
        //开始认证，只要AccessToken没有过期，或者refreshToken的时间节点和AccessToken一致即可
        long size = redisUtils.lGetListSize("user");
        for (long i = 0; i < size; i++) {
            Map<String, Object> onlineUser = (Map<String, Object>) redisUtils.lGetIndex("user", i);
            if (onlineUser.get("username").equals(username)) {
                //判断AccessToken有无过期
                if (!JWTUtils.verify(token)) {
                    throw new TokenExpiredException("token认证失效，token过期，重新登陆");
                } else {
                        return new SimpleAuthenticationInfo(token, token, "ExampleRealm");
                }
            }
        }
        return null;
    }
}